/*
3x3x3-as kocka
Maximálisan 8 kliens csatlakozhat a szerverhez
Kezdeti pozició a kocka 8 sarka.
Szerver által elfogadható parancsok
X+, X-, Y+, Y-, Z+, Z-: Lépések a kockán.  Az adott koordináta (X,Y,Z) növelése(+) vagy csökkentése(-).
Nem teljesíthető lépés esetén nem mozdul és a szerver “NEM LEHET” választ küld.
HOLVAGYOK: A szerver elküldi a kliens koordinátáit a következő formában: “X,Y,Z” pl (“2,2,1”)
Nem értelmezhető parancs esetén a szerver egy “NEM ERTEM” választ küld.
Az a kliens, amely olyan mezőre lép, ahol már tartózkodnak másik kliensek,
akkor a szerver ezeknek a klienseknek egy “RAD LEPTEK” üzenetet küld.

+1 jegy
“?” üzenet esetén a szerver az utolsó 5 eseményt visszaküldi az alábbi formában
Kliens ID, üzenet pl.: “1 Z-”, “3 HOLVAGYOK”
+1 jegy
A szerveren egy karakteresen megjelenített táblán nyomonkövethetjük a játék állását
(a kocka három szeletét síkbeli eltolással ábrázolva).
+1 jegy
Tetszőlegesen paraméterezhető téglatest méret (tetszőleges X,Y,Z dimenziók).
Tetszőlegesen paraméterezhető kliens szám.
Ebben az esetben a kliensek nem a téglatest 8 sarkában, hanem véletlenszerű helyről indulnak.
 */

#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <string.h>
#include <time.h>

#define MAXCLIENT 2
#define listenport "2222"

struct kliens{
	int fd;
	struct kliens* next;
	int x;
	int y;
	int z;
};

struct kliens* kliensek=NULL;
int kliensszam=0;

int listenSocket;
fd_set master;
int fdmax;

int xmax=3;
int ymax=3;
int zmax=3;


void serverlisten(){
	struct addrinfo krit;
	memset(&krit,0,sizeof krit);
	krit.ai_family=AF_UNSPEC;
	krit.ai_socktype=SOCK_STREAM;
	krit.ai_flags=AI_PASSIVE;
	struct addrinfo* res;
	getaddrinfo(NULL,listenport,&krit,&res);
	listenSocket=socket(res->ai_family,res->ai_socktype,res->ai_protocol);
	int v=1;
	setsockopt(listenSocket,SOL_SOCKET,SO_REUSEADDR,&v,sizeof v);
	if(bind(listenSocket,res->ai_addr,res->ai_addrlen)){
		printf("bind error\n");
	}
	listen(listenSocket,MAXCLIENT);
	FD_ZERO(&master);
	FD_SET(listenSocket,&master);
	fdmax=listenSocket;
}

void klienshozzaad(int i){
	struct kliens* kl=(struct kliens*)malloc(sizeof(struct kliens));
	kl->fd=i;
	kl->next=kliensek;
	kliensek=kl;

	switch (kliensszam) {
		case 0:
			kl->x=0;kl->y=0;kl->z=0;
			break;
		case 1:
			kl->x=1;kl->y=0;kl->z=0;
			break;
		case 2:
			kl->x=0;kl->y=1;kl->z=0;
			break;
		case 3:
			kl->x=1;kl->y=1;kl->z=0;
			break;
		case 4:
			kl->x=0;kl->y=0;kl->z=1;
			break;
		case 5:
			kl->x=1;kl->y=0;kl->z=1;
			break;
		case 6:
			kl->x=0;kl->y=1;kl->z=1;
			break;
		case 7:
			kl->x=1;kl->y=1;kl->z=1;
			break;
		default:
			break;
	}





	FD_SET(i,&master);
	if (i>fdmax) {
		fdmax=i;
	}
	kliensszam++;
	char uz[100]="\033[2J\033[0;0f";
	send(i,uz,sizeof uz,0);
	strcpy(uz,"-----------------------\njatek kezdodik\n-----------------------\n");
	send(i,uz,sizeof uz,0);

}

void klienstorol(int i){
	struct kliens* torlendo;
	if (i==kliensek->fd) {
		torlendo=kliensek;
		kliensek=kliensek->next;
	} else {
		struct kliens* elozo=kliensek;
		torlendo=kliensek->next;
		while(torlendo->fd!=i){
			elozo=torlendo;
			torlendo=torlendo->next;
		}

	}
	FD_CLR(i,&master);
	int j;
	int ujfdmax=0;
	for (j = 0; j <= fdmax; ++j) {
		if (FD_ISSET(j,&master)) {
			ujfdmax=j;
		}
	}
	fdmax=ujfdmax;
	kliensszam--;
	close(i);
}

void nemlehet(int i){
	char uz[100]="Nem lehet\n";
	send(i,uz,sizeof uz,0);
}
void nemertem(int i){
	char uz[100]="Nem ertem\n";
	send(i,uz,sizeof uz,0);
}
void kozoscella(int i){
	struct kliens* ckl=kliensek;
	while(ckl->fd!=i){
		ckl=ckl->next;
	}
	struct kliens* kl=kliensek;
	while(kl!=NULL){
		if (kl->fd!=i) {
			if(ckl->x==kl->x && ckl->y==kl->y && ckl->z==kl->z){
				char uz[100]="Rad leptek\n";
				send(kl->fd,uz,sizeof uz,0);
			}
		}
		kl=kl->next;
	}
}
void pozicio(int i){
	struct kliens* kl=kliensek;
	while(kl->fd!=i){
		kl=kl->next;
	}
	char uz[100];
	char n[2];
	memset(uz,0,100);
	strcat(uz,"x: ");
	sprintf(n,"%d",kl->x);
	strcat(uz,n);
	strcat(uz,"\n");

	strcat(uz,"y: ");
	sprintf(n,"%d",kl->y);
	strcat(uz,n);
	strcat(uz,"\n");

	strcat(uz,"z: ");
	sprintf(n,"%d",kl->z);
	strcat(uz,n);
	strcat(uz,"\n");

	send(kl->fd,uz,sizeof uz,0);
}
void kliensuzenet(int i){
	struct kliens* kl=kliensek;
	while(kl->fd!=i){
		kl=kl->next;
	}
	char buff[200];
	memset(buff,0,200);
	int rbytes=recv(i,buff,sizeof buff,0);
	if (rbytes<=0) {
		klienstorol(i);
	} else {
		if(strncmp(buff,"\r\n",2)==0){
			return;
		}
		if(strncmp(buff,"q",1)==0){
			klienstorol(i);
			return;
		}
		if(strncmp(buff,"p",1)==0){
			pozicio(i);
			return;
		}
		if(strncmp(buff,"x+",2)==0){
			if (kl->x==2){
				nemlehet(kl->fd);return;}
			kl->x++;
			kozoscella(i);
			return;
		}
		if(strncmp(buff,"y+",2)==0){
			if (kl->y==2){
				nemlehet(kl->fd);return;}
			kl->y++;
			kozoscella(i);
			return;
		}
		if(strncmp(buff,"z+",2)==0){
			if (kl->z==2){
				nemlehet(kl->fd);return;}
			kl->z++;
			kozoscella(i);
			return;
		}
		if(strncmp(buff,"x-",2)==0){
			if (kl->x==0){
				nemlehet(kl->fd);return;}
			kl->x--;
			kozoscella(i);
			return;
		}
		if(strncmp(buff,"y-",2)==0){
			if (kl->y==0){
				nemlehet(kl->fd);return;}
			kl->y--;
			kozoscella(i);
			return;
		}
		if(strncmp(buff,"z-",2)==0){
			if (kl->z==0){
				nemlehet(kl->fd);return;}
			kl->z--;
			kozoscella(i);
			return;
		}
		nemertem(i);
	}
}

void processloop(){
	fd_set readfd;
	while(1){
		FD_ZERO(&readfd);
		readfd=master;
		select(fdmax+1,&readfd,NULL,NULL,NULL);
		int i;
		for (i = 0; i <= fdmax; ++i) {
			if(FD_ISSET(i,&readfd)){
				if (i==listenSocket) {
					struct sockaddr sa;
					socklen_t sl=sizeof sa;
					int ujfd=accept(listenSocket,&sa,&sl);
					if (kliensszam<MAXCLIENT) {
						klienshozzaad(ujfd);
					} else {
						char* uz="limit\n";
						send(ujfd,uz,sizeof uz,0);
						close(ujfd);
					}
				} else {
					kliensuzenet(i);
				}
			}
		}
	}
}

int main(int argc, char **argv) {
	serverlisten();
	processloop();
	return 0;
}

